💡 AI 인사이트

🤖 AI가 여기에 결과를 출력합니다...

댓글 커뮤니티

쿠팡이벤트

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

검색

    로딩 중이에요... 🐣

    [코담] 웹개발·실전 프로젝트·AI까지, 파이썬·장고의 모든것을 담아낸 강의와 개발 노트

    12 포스트 등록 화면 구성 (장고 Form 활용) | ✅ 편저: 코담 운영자

    12강 - 포스트 등록 화면 구성 (장고 Form 활용)

    등록 화면 - form


    ✨ 이번 강의 목표

    • 장고 Form 클래스를 활용해 사용자 게시물 등록 처리
    • 폼 유효성 검사 및 템플릿 연동 처리
    • form.as_p 렌더링과 템플릿 block 구조 이해

    1. 폼 클래스 정의 (CreatePostForm)

    posts/forms.py

    from django import forms
    from .models import Post
    
    class CreatePostForm(forms.ModelForm):
        class Meta:
            model = Post
            fields = ['caption', 'image']
            labels = {
                'caption': '내용',
                'image': '사진'
            }
    
        def clean_caption(self):
            caption = self.cleaned_data.get("caption")
            if len(caption) < 5:
                raise forms.ValidationError("내용은 최소 5자 이상이어야 합니다.")
            return caption
    
        def clean_image(self):
            image = self.cleaned_data.get("image")
            if image is None:
                raise forms.ValidationError("이미지를 업로드해야 합니다.")
            if not image.name.lower().endswith((".png", ".jpg", ".jpeg")):
                raise forms.ValidationError("지원하는 이미지 형식은 PNG, JPG, JPEG입니다.")
            return image
    

    ✅ 설명

    • ModelForm을 상속받아 모델 기반 폼 구성
    • Meta 클래스를 통해 대상 모델과 필드 설정
    • labels로 필드 라벨명 커스터마이징 가능

    2. 뷰에서 폼 처리

    posts/views.py

    from .forms import CreatePostForm
    
    # GET 요청 시: 폼을 생성하여 템플릿으로 전달
    # POST 요청 시: 폼에 데이터 바인딩 후 유효성 검사 및 저장
    
    def post_create(request):
        if request.method == 'POST':
            form = CreatePostForm(request.POST, request.FILES)
            if form.is_valid():
                post = form.save(commit=False)
                post.author = request.user
                post.save()
                return render(request, 'posts/main.html')
        else:
            form = CreatePostForm()
                return render(request, 'posts/post_create.html', {'form': form})
            else:
                return render(request, 'users/main.html', {'error_message': '권한오류: post 등록에 실패하였습니다.'})
    

    ✅ 설명

    • commit=False는 저장을 지연하고 추가 데이터를 넣기 위해 사용됨 (작성자 설정 등)
    • request.FILES는 이미지 업로드를 위한 데이터 처리용

    3. 템플릿에서 폼 렌더링 (직접 필드 렌더링 방식)

    templates/posts/post_create.html

    {% extends 'posts/base.html' %}
    {% block title %}포스트 생성{% endblock %}
    {% block content %}
    <div class="w-full flex justify-center items-center min-h-screen bg-gray-100">
        <div class="w-2/3 bg-white rounded-lg p-8 shadow-md">
            <h2 class="text-xl font-bold text-center mb-4">포스트 등록</h2>
            <form method="POST" enctype="multipart/form-data">
                {% csrf_token %}
                <div>
        <label for="id_caption" class="block text-sm font-medium text-gray-700 mb-1">내용</label>
        <textarea id="id_caption" name="caption" class="w-full border-gray-300 rounded-lg shadow-sm focus:border-indigo-500 focus:ring-indigo-500" rows="12" required></textarea>
        {% if form.caption.errors %}
            <p class="text-sm text-red-500 mt-1">{{ form.caption.errors.0 }}</p>
        {% endif %}
    </div>
    
    <div>
        <label for="id_image" class="block text-sm font-medium text-gray-700 mb-1">사진</label>
        <input required id="id_image" type="file" name="image" class="w-full file:mr-4 file:py-2 file:px-4 file:rounded-lg file:border-0 file:bg-indigo-600 file:text-white file:font-medium file:cursor-pointer file:hover:bg-indigo-500" />
        {% if form.image.errors %}
            <p class="text-sm text-red-500 mt-1">{{ form.image.errors.0 }}</p>
        {% endif %}
    </div>
                <button type="submit" class="mt-4 w-full py-2 bg-blue-600 text-white font-semibold rounded">등록하기</button>
            </form>
        </div>
    </div>
    {% endblock %}
    

    ✅ 설명

    • form.as_p는 각 필드를 <p> 태그로 감싸 렌더링
    • enctype="multipart/form-data"는 이미지 업로드 시 필수 설정
    • csrf_token은 보안상 필수 입력

    4. 유효성 검사와 required 처리

    문제 상황:

    사용자가 내용 또는 이미지를 비워도 저장되는 문제

    해결 방법:

    • 모델의 blank=False 설정 필요:
    caption = models.TextField(blank=False)
    image = models.ImageField(upload_to='posts/', blank=False)
    
    • blank=False: 폼에서 빈 입력 허용하지 않음 (required 역할)
    • null=False: DB에서 반드시 값이 있어야 함

    → 두 필드 모두 필수 입력값으로 처리됨


    ✅ 정리

    • ModelForm을 활용하면 입력 필드 선언 없이 모델 기반 폼 생성 가능
    • 뷰에서는 form.is_valid()를 통해 유효성 검사를 거쳐 저장 처리
    • 템플릿에서 각 필드를 직접 구성하면 Tailwind 스타일을 세밀하게 적용할 수 있음
    • blank=False 설정으로 필수 입력값 제한 가능

    👉 다음 강의에서는 메인 피드(index.html)에서 등록된 게시글 리스트를 출력합니다.

    TOP
    preload preload